﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Media3D;

namespace Wpf3dTestApp
{
    public class FirstPersonCameraController
    {
        private readonly Dictionary<Key, Action> registeredKeyActions;
        private readonly Viewport3D viewport;

        public FirstPersonCameraController(Viewport3D viewport)
        {
            this.viewport = viewport;
            this.registeredKeyActions = new Dictionary<Key, Action>();

            this.Speed = 0.2;
            this.RegisterDefaultKeyBindings();
        }

        public Point3D LookDirection
        {
            get
            {
                return this.Camera.LookDirection.ToPoint().UnitVector();
            }
        }

        public Point3D UpDirection
        {
            get
            {
                return this.Camera.UpDirection.ToPoint().UnitVector();
            }
        }

        public Point3D RightDirection
        {
            get
            {
                return this.LookDirection.VectorProduct(this.UpDirection).UnitVector();
            }
        }

        public double Speed { get; set; }

        private PerspectiveCamera Camera
        {
            get
            {
                return (PerspectiveCamera)this.viewport.Camera;
            }
        }

        public void RegisterKeyAction(Key key, Action action)
        {
            this.registeredKeyActions[key] = action;
        }

        public void MoveForward()
        {
            this.TranslateCamera(this.LookDirection);            
        }

        public void MoveBack()
        {
            this.TranslateCamera(this.LookDirection.Reverse());
        }

        public void MoveRight()
        {
            this.TranslateCamera(this.RightDirection);
        }

        public void MoveLeft()
        {
            this.TranslateCamera(this.RightDirection.Reverse());
        }

        public void MoveUp()
        {
            this.TranslateCamera(this.UpDirection);
        }

        public void MoveDown()
        {
            this.TranslateCamera(this.UpDirection.Reverse());
        }

        private void RegisterDefaultKeyBindings()
        {
            this.RegisterKeyAction(Key.W, this.MoveForward);
            this.RegisterKeyAction(Key.A, this.MoveLeft);
            this.RegisterKeyAction(Key.S, this.MoveBack);
            this.RegisterKeyAction(Key.D, this.MoveRight);

            this.RegisterKeyAction(Key.Up, this.MoveForward);
            this.RegisterKeyAction(Key.Left, this.MoveLeft);
            this.RegisterKeyAction(Key.Down, this.MoveBack);
            this.RegisterKeyAction(Key.Right, this.MoveRight);

            this.RegisterKeyAction(Key.PageUp, this.MoveUp);
            this.RegisterKeyAction(Key.PageDown, this.MoveDown);
        }

        private void TranslateCamera(Point3D directionVector)
        {
            Point3D translation = directionVector.UnitVector().Multiply(this.Speed);
            this.Camera.Position = this.Camera.Position.Plus(translation);
        }
    }
}
